#include "sMsg.h"

#include <Poco/DOM/DOMParser.h>
#include <Poco/DOM/NodeFilter.h>
#include <Poco/DOM/NamedNodeMap.h>
#include <Poco/DOM/AutoPtr.h>
#include "misc/Interface.h"
#include "server/net/NetworkControl.h"
#include "misc/Debug.h"
#include "sKeepAlive.h"
#include "sAnnounce.h"
#include "sDiscovery.h"
#include "sRegister.h"
#include "sUnRegister.h"
#include "sPut.h"
#include "sGet.h"
#include "sExecute.h"
#include "sData.h"
#include "sAck.h"
/*********************************************************/
using Poco::XML::XMLString;
using Poco::XML::DOMParser;
using Poco::XML::Document;
using Poco::XML::NodeIterator;
using Poco::XML::NodeFilter;
using Poco::XML::NamedNodeMap;
using Poco::XML::AutoPtr;
/*********************************************************/
sMsg* sMsg::deserialize(const std::string& xml)
{
	DOMParser 		parser;		// Parser that will parse the xml strings
	std::string		type;		// The type string of the job
	unsigned long		id;		// Temporary id
	
	AutoPtr<Document> pDoc = parser.parseString( xml );	// Parse the string into memory
	NodeIterator it(pDoc, NodeFilter::SHOW_ELEMENT);	// Node iterator to access the nodes
	Poco::XML::Node* pNode = it.nextNode();			// Fetch the root node from the iterator

	// First node should be the root node, which is in our case "GS"
	if (( !pNode ) || ( pNode->nodeName() != "GS" )) {
		throw (std::logic_error("Attempt to deserialize an invalid packet! Invalid root node found or no root node present!"));
	} else {
		if ( pNode->hasAttributes() ) {
			NamedNodeMap *nnm = pNode->attributes();
			id = atoi(nnm->getNamedItem("id")->nodeValue().c_str());
			nnm->release();
		} else {
			throw ( std::logic_error("No id attribute found in the root node, invalid packet!"));
		}
	}
		
	// Get the next node, this should be the job node, with an attribute specifying the type of job
	pNode = it.nextNode();
	sMsg* msg = 0;
	if (( pNode ) && ( pNode->nodeName() == "Announce" )) {
		msg = new sAnnounce;
	} else if (( pNode ) && ( pNode->nodeName() == "Discovery" )) {
		msg = new sDiscovery;
	} else if (( pNode ) && ( pNode->nodeName() == "Register" )) {
		msg = new sRegister;
	} else if (( pNode ) && ( pNode->nodeName() == "UnRegister" )) {
		msg = new sUnRegister;
	} else if (( pNode ) && ( pNode->nodeName() == "Get" )) {
		msg = new sGet;
	} else if (( pNode ) && ( pNode->nodeName() == "Put" )) {
		msg = new sPut;
	} else if (( pNode ) && ( pNode->nodeName() == "Execute" )) { 
		msg = new sExecute;
	} else if (( pNode ) && ( pNode->nodeName() == "Data" )) {
		msg = new sData;
	} else if (( pNode ) && ( pNode->nodeName() == "ACK" )) {
		msg = new sAck;
	} else if (( pNode ) && ( pNode->nodeName() == "KeepAlive" )) {
		msg = new sKeepAlive;
	} else {
		throw (std::logic_error("Unknown packet contents, or incorrect packet data order!"));
	}

	msg->deserialize(it);
	if ( msg ) {
		msg->setID(id);
	}

	return msg;
}
/*********************************************************/
void sMsg::ack() const
{
	NetworkControl& nc = NetworkControl::Instance();

	sMsg* ack = getAck();
	nc.mutex->lock();
	nc.unicast->sendTo(ack->serialize(), ack->getSenderAddr().toString());
	nc.mutex->unlock();	
	delete( ack );
}
/*********************************************************/
sMsg* sMsg::getAck() const
{
	sMsg* ack = new sAck;
	ack->setSenderAddr(addr);
	ack->setID(id);
	return ack;
}
/*********************************************************/
void sMsg::setID(const unsigned long id)
{
	sMsg::id = id;
}
/*********************************************************/
unsigned long sMsg::getID() const
{
	return id;
}
/*********************************************************/
void sMsg::setSenderAddr(const Poco::Net::SocketAddress& addr)
{
	sMsg::addr = addr;
}
/*********************************************************/
Poco::Net::SocketAddress sMsg::getSenderAddr() const
{
	return sMsg::addr;
}
/*********************************************************/
